﻿namespace AlgoHero.Modelo
{
    using System;
    using System.Text;
    using System.Xml;
    using System.Collections;
    using System.Collections.Generic;
    
    public class Nota
    {
        #region Atributos

        private string nombre;
        private Figura figuraMusical;
        private double frecuencia;

        #endregion

        #region Constructor

        public Nota(string nombre, Figura figuraMusical)
        {
            /* Precondiciones: nombre debe un nombre nota musical válido.
             * figuraMusical debe ser la figura musical que corresponde a la nota musical.
             */
            this.figuraMusical = figuraMusical;

            //Lanza ArgumentException si el nombre no es correcto
            this.frecuencia = this.CalcularFrecuencia(nombre);
            this.nombre = nombre.ToUpper();                  
        }

        public Nota(XmlElement nodo)
        {
            XmlAttributeCollection atributosNodoNota = nodo.Attributes;

            string nombreNota = atributosNodoNota.GetNamedItem("nombre").Value;
            string sFiguraMusical = atributosNodoNota.GetNamedItem("figuraMusical").Value;
            int figuraMusical = Convert.ToInt32(sFiguraMusical);
            if (!Enum.IsDefined(typeof(Figura), figuraMusical))
            {
                throw new ArgumentException("Figura musical de nota inválida.");
            }

            this.nombre = nombreNota;
            this.figuraMusical = (Figura)figuraMusical;
            this.frecuencia = this.CalcularFrecuencia(this.nombre);
        }

        #endregion

        #region Métodos

        private double CalcularFrecuencia(string nombre)
        {
            /* Precondición: nombre debe ser el nombre de una nota musical válida.
             * Postcondición: Devuelve la frecuencia de la nota ingresada.
             * Caso contrario, si la nota es inválida, se lanza una excepción ArgumentException.
             */
            string[] Nombres = { "DO", "DO#", "RE", "RE#", "MI", "FA", "FA#", "SOL", "SOL#", "LA", "LA#", "SI", "SILENCIO" };
            double[] Frecuencias = { 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 0.0 };
            List<string> lstNombres = new List<string>(Nombres);

            if (lstNombres.LastIndexOf(nombre.ToUpper()) != -1)
            {
                return Frecuencias[lstNombres.IndexOf(nombre.ToUpper())];
            }
            else
            {
                throw new ArgumentException("La nota ingresada es inválida");
            }
        }

        internal void SerializarEn(XmlDocument documento, XmlNode nodoPadre)
        {
            XmlNode nodoNota = documento.CreateNode(XmlNodeType.Element, "Nota", "");

            XmlAttribute attNombre = documento.CreateAttribute("nombre");
            attNombre.Value = this.nombre;

            XmlAttribute attFiguraMusical = documento.CreateAttribute("figuraMusical");
            attFiguraMusical.Value = ((int)this.figuraMusical).ToString();

            nodoNota.Attributes.Append(attNombre);
            nodoNota.Attributes.Append(attFiguraMusical);
                        
            nodoPadre.AppendChild(nodoNota);            
        }
        
        public override bool Equals(object obj) 
        {
            Nota otraNota;

            try
            {
                otraNota = (Nota)obj;
                return (this == otraNota);
            }
            catch
            {
                return false;
            }
        }

        public static bool operator ==(Nota unaNota, Nota otraNota)
        {
            return ((unaNota.Frecuencia == otraNota.Frecuencia) && (0==unaNota.FiguraMusical.CompareTo(otraNota.FiguraMusical))
                     && (unaNota.Nombre == otraNota.Nombre));
        }
        public static bool operator !=(Nota unaNota, Nota otraNota)
        {
            return !(unaNota == otraNota);
        }
        
        #endregion

        #region Propiedades

        public string Nombre
        {
            get { return this.nombre; }
        }

        public Figura FiguraMusical
        {
            get { return figuraMusical; }
            //set { figuraMusical = value; }
        }

        public double Frecuencia
        {
            get { return this.frecuencia; }
        }

        #endregion
    }
}

